from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection
from decimal import Decimal
import json
from django import http
from django.utils import timezone
from django.db import transaction

from users.models import Address
from meiduo_mall.utils.views import LoginRequiredMixin, LoginRequiredJSONMixin
from goods.models import SKU
from orders.models import OrderInfo,OrderGoods
from meiduo_mall.utils.response_code import RETCODE
# Create your views here.


# class MyOrdersinfoView(LoginRequiredMixin,View):
#     """我的订单页面"""
#     def get(self,request):
#         """提供我的订单页面"""
#
#         render(request,'user_center_order.html')
#         pass






class OrderSuccessView(LoginRequiredMixin,View):
    """提交订单成功页面"""

    def get(self,request):
        """提供递交订单成功页面"""
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method':pay_method,
        }


        return  render(request, 'order_success.html', context)


class OrderCommitView(LoginRequiredJSONMixin,View):
    """提交订单"""
    def post(self,request):
        """保存订单基本信息和商品信息"""
        # 接受参数
        json_dict =json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('缺少必传参数')
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('参数address_id错误')
        # 判断pay_method是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数pay_method错误')

        # 明显的开启一次事务
        with transaction.atomic():
            # 在数据库操作之前需要指定保存点, 保存数据库最初的状态
            save_id = transaction.savepoint()

            # 暴力回滚
            try:
                # 获取登陆用户
                user = request.user
                # 获取订单编号: 时间 + 用户id(user_id) == '20200926114800000001'
                order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
                # 保存订单基本信息(一)
                order = OrderInfo.objects.create(
                            order_id= order_id,
                            user = user,
                            address = address,
                            total_count = 0,
                            total_amount = Decimal(0.00),
                            freight = Decimal(10.00),
                            pay_method = pay_method,
                            # status = 'UNPAID' if pay_method == 'ALIPAY' else 'UNSEND'
                            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND']

                )


                # 订单商品信息(多)

                # 查询出购物车中被勾选的商品信息
                # 与rendis创建链接,
                rendis_conn = get_redis_connection('carts')
                # 查询redis中的商品
                rendis_carts = rendis_conn.hgetall('carts_%s' % user.id)
                # 查询redis中被勾选的商品
                rendis_selected = rendis_conn.smembers('selected_%s' % user.id)

                # 构造购物车中被选中商品数据
                new_carts_dict = {}
                for sku_id in rendis_selected:
                    new_carts_dict[int(sku_id)] = int(rendis_carts[sku_id])

                # 获取被勾选的商品sku_id
                sku_ids = new_carts_dict.keys()

                for sku_id in sku_ids:

                    # 每个商品都有多次下单的机会,知道库存不足
                    while True:
                        # 读取购物车商品信息
                        sku = SKU.objects.get(id=sku_id) # 查询商品和库存信息时,不能出现缓存,所以不用 filter(id__in=sku_id)


                        # 获取原始的库存和销量
                        origin_stork = sku.stock
                        origin_sales = sku.sales

                        # 获取要提交订单的商品数量
                        sku_count = new_carts_dict[sku.id]
                        # 判断商品数量是否大于库存,如果大于,响应'库存不足'
                        if sku_count > origin_stork:

                            # 库存不足,回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code':RETCODE.STOCKERR, 'errmsg':'库存不足'})

                        # #SkU 减库存,加销量
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()

                        new_stock = origin_stork - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stork ).update(stock=new_stock, sales=new_sales)
                        # 如果在更新数据时,原始数据变化了,返回0 , 表示有资源抢夺
                        if result == 0:
                            # 库存10 要买1个 但是下单时,有资源抢夺,被买走1个,剩下9个,如果库存依然满足 继续下单,直到库存不足为止
                            # return http.JsonResponse('下单失败')
                            continue

                        #SPU 加销量
                        sku.spu.sales += sku_count
                        sku.spu.save()

                        OrderGoods.objects.create(
                            order= order,
                            sku = sku,
                            count = sku_count,
                            price = sku.price,
                        )

                        # 累加订单商品的数量和总价到订单基本信息表
                        order.total_count += sku_count
                        order.total_amount += sku_count * sku.price

                        # 下单成功, 记得break
                        break

                # 再加最后的运费
                order.total_amount += order.freight
                order.save()

            except Exception as e:

                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

            # 数据库操作成功, 明显的提交一次事务
            transaction.savepoint_commit(save_id)
            return http.JsonResponse({'code':RETCODE.OK, 'errmsg':'ok', 'order_id': order_id})


class OrderSettlementView(LoginRequiredMixin,View):
    """结算订单"""
    def get(self,request):
        """查询并展示要结算的订单数据"""
        user = request.user
        # 查询用户收获地址: 查询登陆用户没有被删除的地址
        try:
            addresses = Address.objects.filter(user=user,is_deleted=False)
        except Exception as e:
            # 如果没有查询出地址,可以去编辑收获地址
            addresses = None

        # 查询购物车中已勾选的商品数据(Rendis)
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        redis_selected = redis_conn.smembers('selected_%s' % user.id)

        # 构造购物车中被勾选商品的数据
        new_cart_dict = {}
        for sku_id in redis_selected:
            new_cart_dict[int(sku_id)] = int(redis_cart[sku_id])

        # 遍历new_cart_dict取出 其中的 sku_id 和 count
        # 获取所有被勾选商品的sku_id
        sku_ids = new_cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)

        total_count = 0
        total_amount = Decimal(0.00)

        # 取出所有的skus
        for sku in skus:
            # 遍历skus给每个sku补充count(数量)和amount(小计)
            sku.count = new_cart_dict[sku.id]
            sku.amount = sku.price * sku.count # Decimal类型

            #累加数量和金额
            total_count += sku.count
            total_amount += sku.amount # 类型不同 不能运算

        # 指定默认的邮费
        freight = Decimal(10.00)


        # 构造上下文
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count':total_count,
            'total_amount':total_amount,
            'freight':freight,
            'payment_amount':total_amount + freight,
        }
        return render(request,'place_order.html', context)